{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Capacitance matrix and LOM analysis\n",
    "### Prerequisite\n",
    "You need to have a working local installation of Ansys."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Create the design in Metal"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%reload_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import qiskit_metal as metal\n",
    "from qiskit_metal import designs, draw\n",
    "from qiskit_metal import MetalGUI, Dict, Headings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design = designs.DesignPlanar()\n",
    "gui = MetalGUI(design)\n",
    "\n",
    "from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket\n",
    "from qiskit_metal.qlibrary.tlines.meandered import RouteMeander"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design.variables['cpw_width'] = '15 um'\n",
    "design.variables['cpw_gap'] = '9 um'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### In this example, the design consists of 4 qubits and 4 CPWs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Allow running the same cell here multiple times to overwrite changes\n",
    "design.overwrite_enabled = True\n",
    "\n",
    "## Custom options for all the transmons\n",
    "options = dict(\n",
    "    # Some options we want to modify from the defaults\n",
    "    # (see below for defaults)\n",
    "    pad_width = '425 um', \n",
    "    pocket_height = '650um',\n",
    "    # Adding 4 connectors (see below for defaults)\n",
    "    connection_pads=dict(\n",
    "        readout = dict(loc_W=+1,loc_H=-1, pad_width='200um'),\n",
    "        bus1 = dict(loc_W=-1,loc_H=+1, pad_height='30um'),\n",
    "        bus2 = dict(loc_W=-1,loc_H=-1, pad_height='50um')\n",
    "    )\n",
    ")\n",
    "\n",
    "## Create 4 transmons\n",
    "\n",
    "q1 = TransmonPocket(design, 'Q1', options = dict(\n",
    "    pos_x='+2.42251mm', pos_y='+0.0mm', **options))\n",
    "q2 = TransmonPocket(design, 'Q2', options = dict(\n",
    "    pos_x='+0.0mm', pos_y='-0.95mm', orientation = '270', **options))\n",
    "q3 = TransmonPocket(design, 'Q3', options = dict(\n",
    "    pos_x='-2.42251mm', pos_y='+0.0mm', orientation = '180', **options))\n",
    "q4 = TransmonPocket(design, 'Q4', options = dict(\n",
    "    pos_x='+0.0mm', pos_y='+0.95mm', orientation = '90', **options))\n",
    "\n",
    "RouteMeander.get_template_options(design)\n",
    "\n",
    "options = Dict(\n",
    "        lead=Dict(\n",
    "            start_straight='0.2mm',\n",
    "            end_straight='0.2mm'),\n",
    "        trace_gap='9um',\n",
    "        trace_width='15um')\n",
    "\n",
    "def connect(component_name: str, component1: str, pin1: str, component2: str, pin2: str,\n",
    "            length: str, asymmetry='0 um', flip=False, fillet='90um'):\n",
    "    \"\"\"Connect two pins with a CPW.\"\"\"\n",
    "    myoptions = Dict(\n",
    "        fillet=fillet,\n",
    "        hfss_wire_bonds = True,\n",
    "        pin_inputs=Dict(\n",
    "            start_pin=Dict(\n",
    "                component=component1,\n",
    "                pin=pin1),\n",
    "            end_pin=Dict(\n",
    "                component=component2,\n",
    "                pin=pin2)),\n",
    "        total_length=length)\n",
    "    myoptions.update(options)\n",
    "    myoptions.meander.asymmetry = asymmetry\n",
    "    myoptions.meander.lead_direction_inverted = 'true' if flip else 'false'\n",
    "    return RouteMeander(design, component_name, myoptions)\n",
    "\n",
    "asym = 140\n",
    "cpw1 = connect('cpw1', 'Q1', 'bus2', 'Q2', 'bus1', '6.0 mm', f'+{asym}um')\n",
    "cpw2 = connect('cpw2', 'Q3', 'bus1', 'Q2', 'bus2', '6.1 mm', f'-{asym}um', flip=True)\n",
    "cpw3 = connect('cpw3', 'Q3', 'bus2', 'Q4', 'bus1', '6.0 mm', f'+{asym}um')\n",
    "cpw4 = connect('cpw4', 'Q1', 'bus1', 'Q4', 'bus2', '6.1 mm', f'-{asym}um', flip=True)\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Capacitance Analysis and LOM derivation using the analysis package - most users"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Capacitance Analysis\n",
    "Select the analysis you intend to run from the `qiskit_metal.analyses` collection.<br>\n",
    "Select the design to analyze and the tool to use for any external simulation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.analyses.quantization import LOManalysis\n",
    "c1 = LOManalysis(design, \"q3d\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(optional) You can review and update the Analysis default setup following the examples in the next two cells."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# example: update single setting\n",
    "c1.sim.setup.max_passes = 6\n",
    "# example: update multiple settings\n",
    "c1.sim.setup_update(solution_order = 'Medium', auto_increase_solution_order = 'False')\n",
    "\n",
    "c1.sim.setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Analyze a single qubit with 2 endcaps using the default (or edited) analysis setup. Then show the capacitance matrix (from the last pass).\n",
    "\n",
    "You can use the method `run()` instead of `sim.run()` in the following cell if you want to run both cap extraction and lom analysis in a single step. If so, make sure to also tweak the setup for the lom analysis. The input parameters are otherwise the same for the two methods. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "c1.sim.run(components=['Q1'], open_terminations=[('Q1', 'readout'), ('Q1', 'bus1'), ('Q1', 'bus2')])\n",
    "c1.sim.capacitance_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(otional - case-dependent)<br>If the previous cell was interrupted due to license limitations and for any reason you finally manually launched the simulation from the renderer GUI (outside qiskit-metal) you might be able to recover the simulation results by uncommenting and executing the following cell"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#c1.sim._get_results_from_renderer()\n",
    "#c1.sim.capacitance_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last variables you pass to the `run()` or `sim.run()` methods, will be stored in the `sim.setup` dictionary under the key `run`. You can recall the information passed by either accessing the dictionary directly, or by using the print handle below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# c1.setup.run    <- direct access\n",
    "c1.sim.print_run_args()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can re-run the analysis after varying the parameters.<br>\n",
    "Not passing the parameter `components` to the `sim.run()` method, skips the rendering and tries to run the analysis on the latest design. If a design is not found, the full metal design is rendered."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.setup.freq_ghz = 4.8\n",
    "c1.sim.run()\n",
    "c1.sim.capacitance_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(c1.sim.capacitance_matrix)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lumped oscillator model (LOM)\n",
    "\n",
    "Using capacitance matrices obtained from each pass, save the many parameters of the Hamiltonian of the system. `get_lumped_oscillator()` operates on 4 setup parameters: <br><br>\n",
    "Lj: float <br>\n",
    "Cj: float <br>\n",
    "fr: Union[list, float] <br>\n",
    "fb: Union[list, float] <br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.setup.junctions = Dict({'Lj': 12.31, 'Cj': 2})\n",
    "c1.setup.freq_readout = 7.0\n",
    "c1.setup.freq_bus = [6.0, 6.2]\n",
    "\n",
    "c1.run_lom()\n",
    "c1.lumped_oscillator_all"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.plot_convergence();\n",
    "c1.plot_convergence_chi()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once you are done with your analysis, please close it with `close()`. This will free up resources currently occupied by qiskit-metal to communiate with the tool."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Directly access the renderer to modify other parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.start()\n",
    "c1.sim.renderer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Every renderer will have its own collection of methods. Below an example with q3d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Prepare and run a collection of predefined setups\n",
    "\n",
    "This is equivalent to going to the Project Manager panel in Ansys, right clicking on Analysis within the active Q3D design, selecting \"Add Solution Setup...\", and choosing/entering default values in the resulting popup window. You might want to do this to keep track of different solution setups, giving each of them a different/specific name."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "setup = c1.sim.renderer.new_ansys_setup(name = \"Setup_demo\", max_passes = 6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can directly pass to `new_ansys_setup` all the setup parameters. Of course you will then need to run the individual setups by name as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.renderer.analyze_setup(setup.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Get the capactiance matrix at a different pass\n",
    "\n",
    "You might want to use this if you intend to know what was the matrix at a different pass of the simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Using the analysis results, get its capacitance matrix as a dataframe.\n",
    "c1.sim.renderer.get_capacitance_matrix(variation = '', solution_kind = 'AdaptivePass', pass_number = 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Code to swap rows and columns in capacitance matrix\n",
    "from qiskit_metal.analyses.quantization.lumped_capacitive import df_reorder_matrix_basis\n",
    "\n",
    "df_reorder_matrix_basis(fourq_q3d.get_capacitance_matrix(), 1, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Close the renderer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
